package com.lhy.tool.patchplugin.strategy;

import com.lhy.tool.patchplugin.PatchPluginProperties;
import com.lhy.tool.patchplugin.model.CompileFileWrapper;
import com.lhy.tool.patchplugin.model.FileMapping;
import com.lhy.tool.patchplugin.model.SrcFileWrapper;
import com.lhy.tool.patchplugin.model.TargetFileWrapper;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * 增量包文件环境类
 */
@Component
@Slf4j
public class FileContext {

    @Autowired
    PatchPluginProperties patchPluginProperties;

    @Setter
    @Getter
    List<FileStrategy> fileStrategies = new ArrayList<>();

    private List<TargetFileWrapper> copiedTargetFileWrappers = new ArrayList<>();

    private List<FileMapping> copyList = new ArrayList<>();

    /**
     * 执行生成增量包文件
     *
     * @param srcFiles
     */
    public void executes(Set<File> srcFiles) {
        if (fileStrategies == null || fileStrategies.isEmpty()) {
            throw new NullPointerException("未设置文件策略");
        }
        clearTarageFile();
        srcFiles.forEach(this::execute);
        copyFiles();
    }

    /**
     * 生成器根据是否清空属性来清空目标目录
     */
    @SneakyThrows
    private void clearTarageFile() {
        if (patchPluginProperties.getCleanable()) {
            FileUtils.deleteDirectory(new File(patchPluginProperties.getTargetPath()));
        }
    }

    /**
     * 单个文件的复制处理
     *
     * @param srcFile
     */
    private void execute(File srcFile) {
        //构造源文件
        SrcFileWrapper srcFileWrapper = new SrcFileWrapper(srcFile);
        fileStrategies.stream()
                //获取满足条件的策略类，可能有多个
                .filter(fileStrategy -> fileStrategy.accept(srcFileWrapper))
                .forEach(fileStrategy -> {
                    //获取编译后的文件，可能有多个（内部类）
                    List<CompileFileWrapper> compileFileWrappers = fileStrategy.getCompileFiles(srcFileWrapper);
                    compileFileWrappers.stream()
                            .map(compileFileWrapper -> compileFileWrapper.setSrcFileWrapper(srcFileWrapper))
                            .forEach(compileFileWrapper -> {
                                //获取目标文件 可能有多个（一个jar被多个war引用）
                                List<TargetFileWrapper> targetFile = fileStrategy.getTargetFiles(compileFileWrapper);
                                //构造编译后文件和目标文件的映射关系
                                List<FileMapping> collect = targetFile.stream()
                                        .map(targetFileWrapper -> targetFileWrapper.setCompileFileWrapper(compileFileWrapper))
                                        .map(targetFileWrapper -> new FileMapping(compileFileWrapper, targetFileWrapper))
                                        .collect(Collectors.toList());
                                //加入到待复制列表中
                                copyList.addAll(collect);
                            });
                });
    }

    /**
     * 复制文件 生成增量包
     */
    private void copyFiles() {
        log.info("开始复制文件");
        copyList.forEach(fileMapping -> {
            File compileFile = fileMapping.getCompileFileWrapper().getFile();
            String compileFileAbsolutePath = compileFile.getAbsolutePath();
            File targetFile = fileMapping.getTargetFileWrapper().getFile();
            String targetFileAbsolutePath = targetFile.getAbsolutePath();
            //检查目标文件是否已经存在（已经被复制过）
            if (hasCopied(fileMapping.getTargetFileWrapper())) {
                log.trace("已存在，不再复制");
                fileMapping.getTargetFileWrapper().setCopied(true);
            } else {
                try {
                    //不存在，首次复制
                    log.info("开始复制：{}", compileFileAbsolutePath);
                    log.info("一一一到：{}", targetFileAbsolutePath);
                    if (compileFile.exists()) {
                        if (compileFile.isDirectory()) {
                            FileUtils.copyDirectory(compileFile, targetFile, pathname -> false);
                        } else {
                            FileUtils.copyFile(compileFile, targetFile);
                        }
                        //复制完成加入已复制列表
                        copiedTargetFileWrappers.add(fileMapping.getTargetFileWrapper());
                    }
                } catch (IOException e) {
                    log.error("结果：false", e);
                }
                log.info("复制结果：{}", targetFile.exists());
            }
        });
        log.info("复制完成");
    }

    /**
     * 目标文件是否已存在（已经被复制）
     * 判断岗前复制的目标文件是否在已复制目标文件列表中
     *
     * @param targetFileWrapper
     * @return
     */
    private boolean hasCopied(TargetFileWrapper targetFileWrapper) {
        return copiedTargetFileWrappers.stream()
                .anyMatch(targetFileWrapper1 -> targetFileWrapper1.getAbsolutePath().equals(targetFileWrapper.getAbsolutePath()));
    }

}
